﻿using System;
using System.Collections;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text.RegularExpressions;
using System.Threading;

namespace com.fukefu.source
{
    public class Source
    {
        CookieFactory cookieContainer = CookieFactory.GetInstance();
        string useragent = "";
        int timeout = 60000;
        Hashtable ht_301 = new Hashtable();
        //超时时间设置
        public void SetTimeout(int second)
        {
            timeout = second * 1000;
        }
        //代理设置
        WebProxy proxy = null;
        public void SetProxy(string ip, int port)
        {
            SetProxy(ip + ":" + port);
        }
        public void SetProxy(string p)
        {
            proxy = new WebProxy(p);
        }
        public void ClearProxy()
        {
            proxy = null;
        }
        public string GetProxy()
        {
            if (proxy != null)
            {
                return proxy.Address.Authority;
            }
            return null;
        }
        //构造函数
        public Source()
        {
            useragent = new UserAgent().Get();
        }
        public Source(string ua)
        {
            this.useragent = ua;
        }
        //获取状态码
        public int GetHttpStatusCode(string url)
        {
            HttpWebRequest request = CreateHttpWebRequest(url, "");
            request.Method = "GET";
            int code = 404;
            try
            {
                HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                code = Convert.ToInt32(response.StatusCode);
                response.Close();
            }
            catch (Exception e)
            {
                ShowException(e);
            }
            return code;
        }
        //POST方式获取文件流
        public Stream PostStream(string url, string parameter)
        {
            return PostStream(url, parameter, "");
        }
        public Stream PostStream(string url, string parameter, string referer)
        {
            byte[] date = MyFunction.StringtoByte(parameter);
            try
            {
                HttpWebRequest request = CreateHttpWebRequest(url, referer);
                //处理request
                request.Method = "POST";
                request.AllowAutoRedirect = true;
                request.ContentType = "application/x-www-form-urlencoded";
                request.ContentLength = date.Length;
                //发送数据
                Stream outstream = request.GetRequestStream();
                outstream.Write(date, 0, date.Length);
                outstream.Close();
                //处理返回结果
                return ResponseToStream(url, request.GetResponse() as HttpWebResponse);
            }
            catch (Exception e)
            {
                ShowException(e);
                return null;
            }
        }
        //获取图片
        public Image GetImage(string url)
        {
            return GetImage(url, "");
        }
        public Image GetImage(string url, string referer)
        {
            HttpWebRequest request = CreateHttpWebRequest(url, referer);
            Image image = null;
            try
            {
                request.Method = "GET";
                request.AllowAutoRedirect = true;
                HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                image = Bitmap.FromStream(ResponseToStream(url, response));
                response.Close();
            }
            catch (Exception e)
            {
                ShowException(e);
            }
            return image;
        }
        //GET方式获取文件流
        public Stream GetStream(string url)
        {
            return GetStream(url, "");
        }
        public Stream GetStream(string url, string referer)
        {
            HttpWebRequest request = CreateHttpWebRequest(url, referer);
            try
            {
                request.Method = "GET";
                request.AllowAutoRedirect = true;
                return ResponseToStream(url, request.GetResponse() as HttpWebResponse);
            }
            catch (Exception e)
            {
                ShowException(e);
                return null;
            }
        }
        //如果返回为空，继续，三次后返回
        public string GetThreeTimes(string url)
        {
            return GetThreeTimes(url, "");
        }
        public string GetThreeTimes(string url, string referer)
        {
            string html = "";
            int id = 3;
            do
            {
                html = Get(url, referer);
                if (html.Equals(""))
                {
                    Thread.Sleep(1000);
                    id--;
                }
            } while (html.Equals("") && id > 0);
            return html;
        }
        //GET方式
        public string Get(string url)
        {
            return Get(url, "");
        }
        public string Get(string url, string referer)
        {
            string html = "";
            try
            {
                HttpWebRequest request = CreateHttpWebRequest(url, referer);
                request.Method = "GET";
                html = ProcessHttpWebResponse(url, request.GetResponse() as HttpWebResponse);
            }
            catch (Exception e)
            {
                ShowException(e);
            }
            return html;
        }
        //POST方式
        public string Post(string url, string parameter)
        {
            return Post(url, "application/x-www-form-urlencoded", parameter, "");
        }
        public string Post(string url, string parameter, string referer)
        {
            return Post(url, "application/x-www-form-urlencoded", parameter, referer);
        }
        public string Post(string url, string ContentType, string parameter, string referer)
        {
            return Post(url, ContentType, MyFunction.StringtoByte(parameter), referer);
        }
        public string Post(string url, string ContentType, Byte[] date)
        {
            return Post(url, ContentType, date, "");
        }
        public string Post(string url, string ContentType, Byte[] date, string referer)
        {
            try
            {
                HttpWebRequest request = CreateHttpWebRequest(url, referer);
                //处理request
                request.Method = "POST";
                request.ContentType = ContentType;
                request.ContentLength = date.Length;
                //发送数据
                Stream outstream = request.GetRequestStream();
                outstream.Write(date, 0, date.Length);
                outstream.Close();
                //处理返回结果
                return ProcessHttpWebResponse(url, request.GetResponse() as HttpWebResponse);
            }
            catch (Exception e)
            {
                ShowException(e);
                return "";
            }
        }
        //生成HttpWebRequest
        private HttpWebRequest CreateHttpWebRequest(string url, string referer)
        {
            HttpWebRequest request = null;
            request = WebRequest.Create(url) as HttpWebRequest;
            //ip代理
            if (proxy != null)
            {
                request.Proxy = proxy;
            }
            //如果是发送HTTPS请求 
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                //HTTP版本，现在都是1.1
                request.ProtocolVersion = HttpVersion.Version11;
            }
            //浏览器头设置
            request.AllowAutoRedirect = false;
            request.Host = MyFunction.GetHost(url);
            request.UserAgent = useragent;
            request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            request.Headers.Add("Accept-Encoding", "gzip, deflate");
            request.Headers.Add("Accept-Language", "zh-cn,zh;q=0.5");
            request.Headers.Add("Accept-Charset: gb2312,utf-8;q=0.7,*;q=0.7");
            //这个变量是否存在,或具体的值来判断是否是ajax请求或具体是哪一条ajax请求.  所以利用这个不但可以验证请求是否是ajax请求,还可以获取更多的信息.
            //普通http请求的header参数中没有x-requested-with:XMLHttpRequest头信息，而异步的有
            request.Headers.Add("X-Requested-With", "XMLHttpRequest");
            request.Timeout = timeout;
            request.KeepAlive = true;
            //REFERER
            if (!referer.Equals(""))
            {
                request.Referer = referer;
            }
            //Expect: 100-continue
            request.ServicePoint.Expect100Continue = false;
            //添加Cookie
            if (!cookieContainer.Get(url).Equals(""))
            {
                request.Headers.Add("Cookie", cookieContainer.Get(url));
            }
            return request;
        }
        //获取或设置用于验证服务器证书的回调。 
        private bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true;  //总是接受 
        }
        //处理返回的数据流
        private string ProcessHttpWebResponse(string url, HttpWebResponse response)
        {
            string html = "";
            if (response.StatusCode == HttpStatusCode.OK)
            {
                html = MyFunction.StreamToString(ResponseToStream(url, response));
                html = Regex.Replace(html, "\r?\n", "");
                //关闭数据流
                response.Close();
            }
            else if (response.StatusCode == HttpStatusCode.Found)
            {
                //因为到此位置没有经过 ResponseToStream，所以未处理cookie
                cookieContainer.Add(url, response.Headers.Get("set-cookie"));
                string _url = response.Headers["location"];
                //关闭数据流
                response.Close();
                //错过就是错过，忘记了https的特殊情况
                if (!_url.StartsWith("http://") && !_url.StartsWith("https://"))
                {
                    if (!_url.StartsWith("/"))
                    {
                        _url = url.Substring(0, url.LastIndexOf("/") + 1) + _url;
                    }
                    else
                    {
                        _url = url.Substring(0, url.IndexOf("/") + 2) + MyFunction.GetHost(url) + _url;
                    }
                }
                //如果跳转网址相同，防止循环跳转
                if (url.Equals(_url))
                {
                    lock (ht_301)
                    {
                        if (!ht_301.Contains(_url))
                        {
                            ht_301.Add(_url, 1);
                        }
                        else
                        {
                            ht_301[_url] = Convert.ToInt32(ht_301[_url]) + 1;
                        }
                    }
                    if (Convert.ToInt32(ht_301[_url]) > 3)
                    {
                        return "";
                    }
                }
                html = Get(_url, url);
            }
            return html;
        }
        //如果是gzip，可是要解压缩的
        private Stream ResponseToStream(string url, HttpWebResponse response)
        {
            cookieContainer.Add(url, response.Headers.Get("set-cookie"));
            Stream stream = response.GetResponseStream();
            stream.ReadTimeout = timeout;
            //加压缩gzip
            if (response.Headers["Content-Encoding"] != null && response.Headers["Content-Encoding"].IndexOf("gzip") != -1)
            {
                stream = new StreamReader(new GZipStream(stream, CompressionMode.Decompress)).BaseStream;
            }
            return stream;
        }
        //错误信息处理
        private void ShowException(Exception e)
        {

        }
        //设置独立cookie
        public void SetAloneCookieFactory()
        {
            cookieContainer = CookieFactory.GetInstance(false);
        }
        public CookieFactory GetCookieFactory()
        {
            return cookieContainer;
        }
    }
}